<template>
  <div class="material-select">
    <popup ref="popupRef" width="830px" custom-class="body-padding" :title="`选择${tipsText}`" @confirm="handleConfirm"
           @close="handleClose">
      <template v-if="!hiddenUpload" #trigger>
        <div class="clearfix material-select__trigger" @click.stop>
          <draggable class="draggable" v-model="fileList" animation="300" item-key="id">
            <template v-slot:item="{ element, index }">
              <div
                  class="material-preview"
                  :class="{
									'is-disabled': disabled,
									'is-one': limit == 1,
								}"
                  @click="showPopup(index)"
              >
                <del-wrap @close="deleteImg(index)">
                  <file-item :uri="element" :file-size="size" :type="type"></file-item>
                </del-wrap>
                <div class="text-xs text-center operation-btns">
                  <span>{{ $t('material.edit') }}</span>
                  |
                  <span @click.stop="handlePreview(element)">{{ $t('material.view') }}</span>
                </div>
              </div>
            </template>
          </draggable>
          <div
              class="material-upload"
              @click="showPopup(-1)"
              v-show="showUpload"
              :class="{
							'is-disabled': disabled,
							'is-one': limit == 1,
							[uploadClass]: true,
						}"
          >
            <slot name="upload">
              <div
                  class="upload-btn"
                  :style="{
									width: size,
									height: size,
								}"
              >
                <el-icon>
                  <Plus/>
                </el-icon>
                <span>{{ $t('material.add') }}</span>
              </div>
            </slot>
          </div>
        </div>
      </template>
      <el-scrollbar>
        <div class="material-wrap">
          <material ref="materialRef" :type="type" :file-size="fileSize" :limit="meterialLimit" @change="selectChange"/>
        </div>
      </el-scrollbar>
    </popup>
    <preview v-model="showPreview" :url="previewUrl" :type="type"/>
  </div>
</template>

<script lang="ts">
import Draggable from 'vuedraggable';
import Popup from '/@/components/popup/index.vue';
import FileItem from './file.vue';
import Material from './index.vue';
import Preview from './preview.vue';
import {useThrottleFn} from '@vueuse/shared';

export default defineComponent({
  components: {
    Popup,
    Draggable,
    FileItem,
    Material,
    Preview,
  },
  props: {
    modelValue: {
      type: [String, Array],
      default: () => [],
    },
    // 文件类型
    type: {
      type: String,
      default: 'image',
    },
    // 选择器尺寸
    size: {
      type: String,
      default: '100px',
    },
    // 文件尺寸
    fileSize: {
      type: String,
      default: '100px',
    },
    // 选择数量限制
    limit: {
      type: Number,
      default: 1,
    },
    // 禁用选择
    disabled: {
      type: Boolean,
      default: false,
    },
    // 隐藏上传框*(目前在富文本中使用到)
    hiddenUpload: {
      type: Boolean,
      default: false,
    },
    uploadClass: {
      type: String,
      default: '',
    },
    //选择的url排出域名
    excludeDomain: {
      type: Boolean,
      default: false,
    },
  },

  emits: ['change', 'update:modelValue'],
  setup(props, {emit}) {
    const popupRef = ref<InstanceType<typeof Popup>>();
    const materialRef = ref<InstanceType<typeof Material>>();
    const previewUrl = ref('');
    const showPreview = ref(false);
    const fileList = ref<any[]>([]);
    const select = ref<any[]>([]);
    const isAdd = ref(true);
    const currentIndex = ref(-1);
    const {disabled, limit, modelValue} = toRefs(props);
    const tipsText = computed(() => {
      switch (props.type) {
        case 'image':
          return '图片';
        case 'video':
          return '视频';
        case 'file':
          return '文件';
        default:
          return '';
      }
    });

    const showUpload = computed(() => {
      return props.limit - fileList.value.length > 0;
    });
    const meterialLimit: any = computed(() => {
      if (!isAdd.value) {
        return 1;
      }
      if (limit.value == -1) return null;
      return limit.value - fileList.value.length;
    });
    const handleConfirm = useThrottleFn(
        () => {
          const selectUri = select.value.map((item) => (props.excludeDomain ? item.path : item.uri));
          if (!isAdd.value) {
            fileList.value.splice(currentIndex.value, 1, selectUri.shift());
          } else {
            fileList.value = [...fileList.value, ...selectUri];
          }
          handleChange();
        },
        1000,
        false
    );
    const showPopup = (index: number) => {
      if (disabled.value) return;
      if (index >= 0) {
        isAdd.value = false;
        currentIndex.value = index;
      } else {
        isAdd.value = true;
      }
      popupRef.value?.open();
    };

    const selectChange = (val: any[]) => {
      select.value = val;
    };
    const handleChange = () => {
      const valueImg = limit.value != 1 ? fileList.value : fileList.value[0] || '';
      emit('update:modelValue', valueImg);
      emit('change', valueImg);
      handleClose();
    };

    const deleteImg = (index: number) => {
      fileList.value.splice(index, 1);
      handleChange();
    };

    const handlePreview = (url: string) => {
      previewUrl.value = url;
      showPreview.value = true;
    };

    const handleClose = () => {
      nextTick(() => {
        if (props.hiddenUpload) fileList.value = [];
        materialRef.value?.clearSelect();
      });
    };

    watch(
        modelValue,
        (val: any[] | string) => {
          fileList.value = Array.isArray(val) ? val : val == '' ? [] : [val];
        },
        {
          immediate: true,
        }
    );
    provide('limit', props.limit);
    provide('hiddenUpload', props.hiddenUpload);
    return {
      popupRef,
      materialRef,
      fileList,
      tipsText,
      handleConfirm,
      meterialLimit,
      showUpload,
      showPopup,
      selectChange,
      deleteImg,
      previewUrl,
      showPreview,
      handlePreview,
      handleClose,
    };
  },
});
</script>

<style scoped lang="scss">
.material-select {
  .material-upload,
  .material-preview {
    position: relative;
    border-radius: 4px;
    cursor: pointer;
    margin-right: 8px;
    margin-bottom: 8px;
    box-sizing: border-box;
    float: left;

    &.is-disabled {
      cursor: not-allowed;
    }

    &.is-one {
      margin-bottom: 0;
    }

    &:hover {
      .operation-btns {
        display: block;
      }
    }

    .operation-btns {
      display: none;
      position: absolute;
      bottom: 0;
      border-radius: 4px;
      width: 100%;
      line-height: 2;
      color: #fff;
      background-color: rgba(0, 0, 0, 0.3);
    }
  }

  .material-upload {
    :deep(.upload-btn) {
      @apply text-tx-secondary box-border rounded border-br border-dashed border flex flex-col justify-center items-center;
    }
  }
}

.material-wrap {
  min-width: 720px;
  height: 430px;
  @apply border-t border-b border-br;
}
</style>
